;;; Copyright (c) 1999 Massachusetts Institute of Technology
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation; either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, see https://gnu.org/licenses or
;;; write to:
;;;  Free Software Foundatiom, Inc.
;;;  51 Franklin St, Fifth Floor
;;;  Boston, MA 02110-1301
;;;  USA


;DEVICE CODES
DIS==130	;DISPLAY PROCESSOR
DISMAP==134	;MEM PROT & REL
LIPSH==(040000)
NWSTK==LIPSH 3,

ADSTAR:	CONO PI,CLKOFF	;TURN OFF CLOCK TO PREVENT POSSIBLE GOBBLING BY ANOTHER USER
	PUSHJ P,DISCHK	;CHECK IF THIS USER OWNS THE DISPLAY
	JRST CLKONJ	;RESTART THE CLOCK
	SETZM E.SPGH	; QSWI1 switch
	SETZM E.SCLS	; clear clobber switch
	SKIPL	DISUSR	; no user
	CAMN	U,DISUSR	; skips if different index
	JRST	NOCLBR	; dont untie pages
	MOVEM	U,E.SCLS	; else remember to untie
	SKIPA		; and dont hack disusr
NOCLBR:	MOVEM U,DISUSR	;GIVE IT TO HIM IF NO ONE ELSE OWNS IT
	CONO PI,CLKON	;RESTORE THE CLOCK
	CONO DIS,5010	;SET STOP, CLEAR PIA
	XCTR	XR,[HRRZ	A,(C)]	; causes pg ld, fetches droot
	HRRM	A,DSTADD	; remember for restarts
	XCTR	XR,[MOVE	B,(A)]	; load display page
	PUSHJ	P,SWTL	; circular switch gobble
		CIRPSW
	LSH	A,-10.	; page number
	SKIPN	E.SCLS	; clobbering old user index ?
	JRST	RDSCLB	; if not, skip it
	MOVE	U,DISUSR	; old useri
	PUSHJ	P,E.SCLB	; untie pages
	MOVEI	U,0
	EXCH	U,E.SCLS	; clear switch, fetch new usri
	MOVEM	U,DISUSR
RDSCLB:	PUSHJ	P,UPLC	; users pg n into circular pointer
	PUSHJ	P,CHACK	; go in circles
	SKIPL	C	; 4.9 implies real core in loop
	JRST NOTIED	; if not, dont tie down -- still swapped out
	MOVE	T,J	; MEMPNT INDEX
	MOVE	E,D	; MMP INDEX
	PUSHJ	P,E.SPG1	; go tie it down
NOTIED:	PUSHJ	P,LSWPOP	; clear switch
	; now set up E&S dbrs
	MOVEI T,UDBR1A(U)
	HRLI T,<NUVPG/2>_1	;DBL left 1 relative to 10
	MOVEM T,E.SPM+2
	HRRI T,UDBR2A(U)
	MOVEM T,E.SPM+3

	; now start (or restart if from E.SPGI) E&S

RDSTAR:	CONO DIS,515330	;RESET THE WORLD
	SETOM	E.SSYS	;FLAG=MAP ON (USER MODE)
	CONO DIS,515330	;CLEAR 3D CLIPPER
	MOVEI I,1000	;SET COUNT FOR TIMEOUT
	MOVE	H,DSTADD	; fetch c(0)
	MOVEM	H,E.SPM		; store in status block
	MOVSI	H,140000	; status bits -- map high and low
	MOVEM	H,E.SPM+1	; set status
	SKIPA H,[-ADSTN,,ADSTL-1]
	BLKO DIS,H
	CONSO DIS,604000 ;SKIP IF DONE OR ERROR
	SOJG I,.-1
	JUMPL H,.-3
	JUMPE I,CPOPJ	;FAIL IF TIME OUT ON START
	CONSZ DIS,600000	;CHECK FOR EXECUTIVE ERRORS
	JRST ADXIT	;GIVE INTERRUPT, NO SKIP

	AOS (P)
ADCON1:	CONO DIS,400	;RUN
ADXIT:	CONO DIS,222010+DISCHN	;ALARM+MPV+STOP+PIA
	POPJ P,

ADSTPX:	CONSZ DIS,1040	;FAIL TO SKIP IF MEM OR SEL STOP
	JRST ILUUO	;ERROR IF STOP
ADSTOP:	CAME U,DISUSR	;SKIP IF USER OF SCOPE
	JRST URET	;EXIT IF NOT SCOPE USER
ADSTPY:	CONO DIS,5000	; IOSTOP+STOP.INT.OFF
	CONO DIS,300	;LR.PROG+CLR.HIT
	CONSO DIS,640000 ;SKIP IF PARITY, NXM, MPV ON
	JRST	E.SUSM	;MAP IS STILL ON
	CONO DIS,400000	;CLEAR MASTER STUFF (TURNS OFF MAP)
	CONO DIS,400000 ;CLEAR 3D CLIPPER

	AOS E.SSYS	;REMEMBER PAGING IS OFF
E.SUSM:	CONSO DIS,4000	;SKIP IF STOPPED AND READY
	PUSHJ P,UFLS	;ELSE WAIT UNTIL READY
	POPJ P,

ADCONT:	PUSHJ P,ADSTPX	;ILLEGAL IF MEM OR SEL STOP
	PUSHJ	P,E.SFU	; force user mode if necessary
	POPJ	P,0	; gross lossage (hardware)
	JRST ADCON1

ADSTEP:	PUSHJ P,ADSTPX	;ILLEGAL IF MEM OR SEL STOP
	PUSHJ	P,E.SFU	; Force User mode (reloads map and skips)
	POPJ	P,0	; lossage if here
	CONO DIS,40
	POPJ P,

ADWORD:	XCTR	XR,[MOVE J,(J)]	; fetch c(AC)
	PUSHJ P,ADSTOP	;MAKE SURE IT IS STOPPED
	PUSHJ	P,E.SFU	;RELOAD MAP IF NECESSARY
	POPJ	P,0	;MAP NOT IN USER MODE
	DATAO DIS,J
	POPJ P,

ADCLOS:	CAME U,DISUSR
	POPJ P,
	CONO DIS,5010	;STOP, PI OFF
	SETZM	E.SPGW		;CLEAR PAGE WAIT
	PUSHJ	P,SWTL		;LOCK CIRCULAR SWITCH
		CIRPSW
	PUSHJ	P,E.SCLB
	PUSHJ	P,LSWPOP	;RESTORE SWITCH
	SETOM DISUSR
	POPJ P,

DISCHK:	MOVE B,UNAME(U)
	SKIPL T,DISUSR
	CAMN B,UNAME(T)
	AOS (P)

ADRSTA:		;READ STATE, WRITE STATE NOT IN.
ADSSTA:	POPJ P,

;E&S PAGER HAS TO REFERENCE 0 TO INITIALLIZE MAP.
;E&S FORCE USER MODE

E.SFU:	SKIPGE	E.SSYS
	JRST POPJ1		;SKIP IF MAP OFF
E.SFU2:	MOVSI	T,140000	;ENTRY FOR DCRRST
	MOVEM	T,E.SPM+1	;RESETS STATUS
	DATAO	DIS,[NWSTK 1]	;STORE SP AT 0
	PUSHJ	P,E.SWT		;CANNOT UFLS -- NWSTK MIGHT BE REISSUED
	POPJ	P,0		;HARDWARE LOSSAGE
	DATAO	DIS,E.SPM	;OUTPUTS C(0) (RELOADS SP)
	PUSHJ	P,E.SWT
	POPJ	P,0	;LOST
	SETOM	E.SSYS	;REMEMBER MAP ON
	JRST	POPJ1

E.SWT:	PUSH	P,J
	MOVEI	J,100		;COUNT FOR TIMEOUT
	CONSZ	DIS,4000	;STOPPED AND READY? ELSE SKIP
	JRST	POPJJ1		;SKIP RET IF READY
	CONSO	DIS,640000	;OTHER FLAVORS OF LOSSAGE
	SOJG	J,E.SWT+2	;COUNT IF STILL OK
	CONO DIS,10		;STOP FOR GOOD
	JRST	POPJJ		;LOSES, NO SKIP RETURN

ADSTL:	000501052405	;LI DIR,052405(PROGM)
	300541,,[-1,,]	;LOCLA SELINT,[-1,,](1)
	300441,,[102521,,]	;LOCLA CDIR,[102521,,](1)
	302641,,[3777,,3777]	;LOCLSA VIEW,[3777,,3777](1)
	302701,,[377777377777]	;LOCLSA WIND,[377777377777](1)
	100,,0			; (JMP 0) load page map and go
ADSTN==.-ADSTL
EBLK

DSTADD:	000100,,	;JMP TO CODE (FILL IN ADDRESS)

; E&S PAGE MAP STATUS BLOCK
E.SPM:	0	; c(0)
	0	; status word
	0	; dbr low
	0	; dbr high

MXDISP==16.	; maximum number of tied pages
DISPGP:	-MXDISP,,0	; page pointer for mmp pages
DISSWP: BLOCK MXDISP	; MMSWP INDICES TIED
E.SPGW:	0	; if non zero, E&S page wait page
E.SPGH: 0	; flag for QSWI1
E.SCLS:	0	; if non zero, new userI flushing disusr
E.SSYS:	0	; flag for pager on/off
E.SIST: 0	; ststus word at last interrupt

; counts for debugging

E.SNTI: 0	; # pages tied down (total during system run)
E.SNUT: 0	; # pages untied    (should = .-1 after dclose)

E.SREL: 0	; # times pages in DISSWP table were relocated

; end of debug counts


DSTPCT:	-1		; STOP COUNT TO HANDLE REDUNDANT STOPS
DSCONI:	0	;LAST CONI FROM DISPLAY
EBRKA:	0	;INTERRUPT SAVE AC
EBRKU:	0	; DITTO

ESBRK:	0	;HANDLE E&S INTERRUPT

BBLK

	CONSO DIS,7	;PI CHAN ASSIGNED?
	JRST 12,@ESBRK	;NO, CANNOT INTERRUPT
	CONI DIS,DSCONI
	CONO DIS,10	;DEASSIGN PI CHANNEL
	MOVEM U,EBRKU	;SAVE AC'S
	MOVEM A,EBRKA
	MOVEI A,%PILTP	;GIVE "LTPEN" INT (CLASS 3)
	CONSZ DIS,640040	;PAR, NXM, MPV, SELECT
	JRST	E.SFLT	; check page fault
E.SUIN:	SKIPL U,DISUSR
	IORM A,PIRQC(U)
E.SPFR:	MOVE A,EBRKA	;UNSAVE AC'S
	MOVE U,EBRKU
	JRST 12,@ESBRK	;RETURN

E.SFLT:	CONSZ	DIS,200000	; skip if not NXM (ie not fault)
	SKIPL	E.SPM+1	; error bit set in status word ?
	JRST	E.SILM	; if not, real illegal mem
	LDB	U,[121000,,E.SPM+1]	; get page #
	HRROM	U,E.SPGW	; save for loading (LH is flag)
	MOVE	U,E.SPM+1	; get status
	MOVEM	U,E.SIST	; save status for later (debugging)
	LDB	U,[330300,,U]	; access and pgerr
	CAIE	U,2		; read write/first error
	SKIPN	U		; no access -- page fault
	JRST	E.SPFR		; gives a page fault
E.SILM:	SETZM	E.SPGW	; if not page fault, don't rq load
	MOVEI	A,%PIDIS; mem fault bits
	JRST	E.SUINT	; give user interrupt

DCRSTP:	CAMN U,DISUSR	;IS THIS U ON DIS
	AOSE DSTPCT	; HERE IF THIS USER, SKIP IF FIRST CALL TO STOP
	POPJ P,	;RETURN IF NOT
	CONSO DIS,7	; SKIP IF CURRENTLY RUNNING
	POPJ P,		; RETURN IF NOT RUNNING NOW
	CONI DIS,DSCONI	;SAVE STATE FOR RESTART
	CONO DIS,5000	;OTHERWISE STOP IT
DISSTQ:	MOVEI TT,100
	CONSO DIS,4000	;SKIP IF STOP ACTUALLY TAKES HOLD
	SOJG TT,.-1	;TIME-OUT LOOP
	JUMPG TT,CPOPJ	;DID NOT TIME OUT, OK
	CONO DIS,10	;DISABLE DISPLAY (CLEAR PIA)
	AOS DISSTQ	;CAUSE "SYSTEM CLOBBERED" ... ON SYS CONSOLE
	POPJ P,


E.SLPM:	PUSHJ	P,DCRSTP	; stop before loading page map
DCRRST:	CAMN U,DISUSR	;IS THE CURRENT U ON DISPLAY?
	SOSL T,DSTPCT	; SKIP IF LAST START CALL, (FROM MORE THAN 1 STOP)
	POPJ P,	;NO
	AOSE T	;SKIP IF ONLY ONE STOP
	JRST 4,.	;SOME ONE IS OUT OF PHASE!
	MOVE T,DSCONI
	CONSZ DIS,7	;SKIP IF NOT RUNNABLE
	TRNE T,4000	;1=> WAS STOPPED
	POPJ P,	;SO QUIT
	PUSHJ	P,E.SFU2	; load E&S page map
	POPJ	P,0	; lost somehow
	CONO DIS,400	;ELSE SET RUN
	CONO DIS,2000	;THEN ALLOW STOP INT
	POPJ P,

	; tie down hacks

;E.SPCH checks MMSWP ind in T against DISSWP
; R0 if already there, R1 if not. ret index in H

E.SPCH:	MOVSI	H,-MXDISP
	CAMN	T,DISSWP(H)
	POPJ	P,0	; found
	AOBJN	H,.-2	; look some more
	JRST	POPJ1	; not found, skip

E.SCLB:	MOVSI	H,-MXDISP
	SKIPE	T,DISSWP(H)	; VALID IF NON-ZERO
	PUSHJ	P,UNTIE	; UNTIE PAGE IN T (MMSWP INDEX)
	AOBJN	H,E.SCLB+1
	POPJ	P,0

; UNTIE PG  T/ MMSWP index
; 		H/ display table index

UNTIE:	AOS	E.SNUT	; count unties
	PUSH	P,H
	MOVSI	H,-1
	ADDB	H,MMSWP(T)	; sos # exec pgs
	SKIPGE	H	; if less than zero, untied an untied page
	JRST	4,.	; exec pg count < 0
	POP	P,H
	SETZM	DISSWP(H)	; clear table entries
	POPJ	P,0

; ties down page.  T/ MMSWP ind.

E.SPG1:	SKIPL	MEMBLT(T)	; frozen, so dont tie
	PUSHJ	P,E.SPCH	; skips if not there
	POPJ	P,0		; dont tie
	AOS	E.SNTI		; count number of ties.
	MOVSI	H,1
	ADDM	H,MMSWP(T)	; aos # exec pgs
	MOVE	H,DISPGP	; fetch dis pg pointer
	AOBJN	H,.+2
	MOVSI	H,-MXDISP	; reset pointer if table full
	MOVEM	H,DISPGP	; update pointer
	PUSH	P,T	; now checks if slot in use
	SKIPE	T,DISSWP(H)
	PUSHJ	P,UNTIE	; untie page in T
	POP	P,T
	MOVEM	T,DISSWP(H)	; remember mmswp ind
	POPJ	P,0

; E.SPGI called from CFHPI on page in core after fault

E.SPGI:	SKIPGE	U,DISUSR
	JRST	4,.	; why here ?
	HRRO	I,CFHUVP	; user virtul page from CFH...
	CAME	I,E.SPGW	; is the sam as E&S rq ?
	POPJ	P,0		; no, return
	SETOM	E.SPGH		; set flag for QSWI1 (read/write/first hack)
	PUSHJ	P,E.SPG1	; tie down
	SETZM	E.SPGW		; clear page wait
	PUSHJ	P,RDSTART		; restart display
	POPJ	P,0
	POPJ	P,0	; skip return from rdstart if wins
